/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.se2.meteocal.control;
import it.polimi.se2.meteocal.entity.Event;
import it.polimi.se2.meteocal.entity.EventNotification;
import it.polimi.se2.meteocal.entity.Location;
import it.polimi.se2.meteocal.entity.Participation;
import it.polimi.se2.meteocal.entity.ParticipationNotification;
import it.polimi.se2.meteocal.entity.Weather;
import it.polimi.se2.meteocal.helper.DateUtilityMethods;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.Singleton;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;
/**
 *
 * @author Ugo
 */
@Singleton 
public class WeatherSchedule {
    
   
    @EJB
    private LocationManager locationManager;
    @EJB 
    private WeatherManager weatherManager;
    @EJB
    private EventManager eventManager;
    @EJB
    private ParticipationManager participationManager;
    @EJB
    private NotificationManager notificationManager;
    
    private final boolean showdetails=false;
    
    //ogni 3 ore!!! 
      @Schedule(second= "1",minute ="30", hour="*/3" ,persistent = false)
    //@Schedule(second= "15",minute ="*", hour="*" ,persistent = false) 
    public void checkWeatherConditions(){
        System.out.println("cancello tutto");
        weatherManager.deleteAll();
        System.out.println("inizio analisi");
        List<Location> locations = locationManager.getAllLocation();
        for(Location s:locations)
            getWeather(s);
      
    }
    
    //1 volta al giorno alle 04:00:00
      @Schedule(second= "0",minute ="0", hour="4" ,persistent = false)
    //@Schedule(second= "1",minute ="*/2", hour="*" ,persistent = false)
    public void check1dayBadWeather(){
        EmailSender emailSender = new EmailSender();
        System.out.println("Checking events in bad weather conditions - 1 day notification");
        List<Event> events;
        events=eventManager.getAllEvent();
        checkWeatherConditions();
        for(Event e:events)
        {
            Weather weather= weatherManager.getWeatherByLocationAndDate(e.getLocation(), e.getData()); 
            if (weather!=null)
            {
                if(e.isOutdoor() && isBadWeather(weather) && DateUtilityMethods.distanceInDays(e.getData(),true)==1.0)
                {
                    System.out.println("bad conditions 1 day before for event: " + e.getId());
                    List<Participation> participations = participationManager.findParticipationByEventNotRemoved(e);
                    for(Participation p:participations)
                    {
                        ParticipationNotification partnot= notificationManager.findParticipationNotificationByParticipationAndType(p, Long.valueOf(3));
                        if(partnot==null)
                        {
                            partnot= new ParticipationNotification(); 
                            partnot.setParticipation(p);
                            partnot.setType(Long.valueOf(3));
                            partnot.setSeen(false);
                            notificationManager.create(partnot);
                        }
                        /* else
                        {
                            partnot.setSeen(false);
                            notificationManager.edit(partnot);
                        }*/
                      
                    }
                    emailSender.sendEmail1daynotification(participations, e, weather);
                }
            }
        }
    }
    
    // 3 volte al giorno
    //4:15
    //12:15
    //20:15
    @Schedules ({
        @Schedule(second= "0",minute ="15", hour="4" ,persistent = false),
        @Schedule(second= "0",minute ="15", hour="12" ,persistent = false),
        @Schedule(second= "0",minute ="15", hour="20" ,persistent = false)
    })
    //@Schedule(second= "1",minute ="*/1", hour="*" ,persistent = false)
    public void check3daysBadWeather(){
        EmailSender emailSender = new EmailSender();
        System.out.println("Checking events in bad weather conditions - 3 days notification");
        List<Event> events;
        events=eventManager.getAllEvent();
        checkWeatherConditions();
        for(Event e:events)
        {
            Weather weather= weatherManager.getWeatherByLocationAndDate(e.getLocation(), e.getData());
            if (weather!=null)
            {
                if(e.isOutdoor() && isBadWeather(weather) && DateUtilityMethods.distanceInDaysAccurate(DateUtilityMethods.DateAndTime(e.getData(), e.getBeginn()))<=3.0 && DateUtilityMethods.distanceInDaysAccurate(DateUtilityMethods.DateAndTime(e.getData(), e.getBeginn()))>=2.3)
                {
                    List<Weather> weatherchoices = weatherManager.getWeatherByLocation(e.getLocation());
                    for(Weather w:weatherchoices)
                    {
                      System.out.println(w.getDescription());
                      if(w.getDate().after(e.getData())){
                        if(isBadWeather(w)==false)
                        { 
                            System.out.println("found first date with good conditions in "+ w.getlocation() + " on: "+ w.getDate() + " with: "+w.getDescription() + " for event: " + e.getId());
                            EventNotification eventnot = notificationManager.findEventNotificationByEvent(e);
                            if(eventnot==null){
                                notificationManager.create(new EventNotification(e,w.getDate()));
                                emailSender.sendEmail3daysNotification(e, weather, w.getDate());
                            }
                            else
                            {
                                System.out.println("new research for an event already notified for bad conditions");
                                //se da una seconda analisi si ottiene una data differente, creo una nuova notifica all'owner con la nuova data.altrimenti non lo disturbo
                                if (!w.getDate().equals(eventnot.getNewdate()))
                                {
                                    System.out.println("previous value " +eventnot.getNewdate());
                                    System.out.println("new best date on "+ w.getDate());
                                    eventnot.setNewdate(w.getDate());
                                    eventnot.setSeen(false);
                                    notificationManager.edit(eventnot);
                                    emailSender.sendEmail3daysNotification(e, weather, w.getDate());
                                }
                                else
                                    System.out.println("no changed");
                            }
                            break;
                        }
                       }
                    }
                      weatherchoices=null; 
                }
            }
        }
    }
    
    private void getWeather(Location location){
        try {
            String rispostaJson = openWeatherRequest(location.toString());
            System.out.println("Send weather request for: "+location.toString());
            //create JsonReader object
            JsonReader jsonReader = Json.createReader(new StringReader(rispostaJson));
            //get JsonObject from JsonReader
            JsonObject jsonObject = jsonReader.readObject();
            jsonReader.close();
            JsonArray arrayGiorni = jsonObject.getJsonArray("list");
            JsonObject city = jsonObject.getJsonObject("city");
            JsonValue val=city.getJsonString("name");
            String cityy= val.toString();
            System.out.println(val);
            if(!cityy.toLowerCase().contains(location.toString().toLowerCase()))
            {
                System.out.println("city received from the server does not match to that required. not proceed in the analysis");
            }
                
            else
            {
            java.util.Calendar calendar = java.util.Calendar.getInstance();
                
            for(JsonValue giorno : arrayGiorni){
                Weather weather=new Weather();
                String tempmax,tempmin,rain,windspeed,humidity,main=null,description=null,icon=null;
                weather.setLocation(location);
                
                weather.setDate(calendar.getTime());
                calendar.add(java.util.Calendar.DAY_OF_YEAR, 1);
                calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
                calendar.set(java.util.Calendar.MINUTE, 0);
                calendar.set(java.util.Calendar.SECOND, 0);
                calendar.set(java.util.Calendar.MILLISECOND, 0);
                
                JsonReader jsonReader2 = Json.createReader(new StringReader(giorno.toString()));
                JsonObject datiGiorno = jsonReader2.readObject();
                jsonReader2.close();
                
                JsonObject temperature = datiGiorno.getJsonObject("temp");
                    
                tempmax=temperature.getJsonNumber("max").toString();
                weather.setTempmax(tempmax);
                    
                tempmin=temperature.getJsonNumber("min").toString();
                weather.setTempmin(tempmin);
                    
                rain=null;
                try
                {
                    rain=datiGiorno.getJsonNumber("rain").toString();
                }
                catch(Exception e){
                    //la to string non deve avere null. in alcuni casi il server non da il campo json rain
                }
                weather.setRain(rain);
                    
                humidity=datiGiorno.getJsonNumber("humidity").toString();
                weather.setHumidity(humidity);
                    
                windspeed=datiGiorno.getJsonNumber("speed").toString();
                weather.setWindspeed(windspeed);

                for(JsonValue meteo : datiGiorno.getJsonArray("weather"))
                {
                    JsonReader jsonReader3 = Json.createReader(new StringReader(meteo.toString()));
                    JsonObject datiMeteoGiorno = jsonReader3.readObject();
                    jsonReader3.close();
                    main=datiMeteoGiorno.getString("main");
                    icon=datiMeteoGiorno.getString("icon");
                    weather.setMaincond(main);
                    weather.setIcon(icon);
                    description=datiMeteoGiorno.getString("description");
                    weather.setDescription(description);
                }
                if(showdetails)
                {
                    System.out.println("Weather forecast for:"+calendar.getTime());
                    System.out.println("temp max:"+tempmax); 
                    System.out.println("temp min:"+tempmin);
                    System.out.println("rain:"+rain);  
                    System.out.println("humidity:"+humidity);
                    System.out.println("wind speed:"+windspeed);
                    System.out.println("main condition:"+main);
                    System.out.println("description:"+description); 
                    System.out.println("------------------------------");
                }
                weatherManager.create(weather);
            }
            }
        } catch (Exception ex) {
            System.out.println("exception");
            //Logger.getLogger(WeatherSchedule.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
        
    private String openWeatherRequest(String location) throws Exception{
        String url = "http://api.openweathermap.org/data/2.5/forecast/daily?q="+location+"&mode=json&units=metric&cnt=16";
        URL obj = new URL(url);
	HttpURLConnection con = (HttpURLConnection) obj.openConnection();
	con.setRequestMethod("GET");
	BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
	String inputLine;
	StringBuilder response = new StringBuilder();
	while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
	}
	in.close();
	return response.toString();
    }
     
    private boolean isBadWeather(Weather weather){
        String description = weather.getDescription().toLowerCase();
        if(description.contains("rain")||description.contains("drizzle")||description.contains("thunderstorm")|| description.contains("snow")|| description.contains("tornado") ||description.contains("storm")||description.contains("hurricane")||description.contains("gale"))
            return true;
        return false;
    }   
    
   // ONLY FOR TEST
    public void setEventManager(EventManager em) {
        this.eventManager=em;
    }

    public void setNotificationManager(NotificationManager nm) {
        this.notificationManager=nm;
    }
    
    public void setWeatherManager(WeatherManager wm){
        this.weatherManager=wm;
    }
    
    public void setLocationManager(LocationManager lm){
        this.locationManager=lm;
    }

    public void setParticipationManager(ParticipationManager pm) {
       this.participationManager=pm;
    }

}